/*
 * bsp.hpp
 *
 *  Created on: Jan 22, 2014
 *      Author: elazar
 */

#ifndef BSP_HPP_
#define BSP_HPP_
#include "mcbsp.hpp"
#include <string>

namespace Bsp {

template<typename T>
void push_reg_async(T& t) {
	bsp_push_reg(&t, sizeof(t));
}

template<typename T>
void push_reg(T& t) {
	push_reg_async(t);
	bsp_sync();
}

template<typename T, typename... Args>
void push_reg(T& t, Args... args) {
	push_reg(t);
	push_reg(args...);
}

template<typename T>
void get(int pid, T& source, T& dst) {
	bsp_get(pid, &source, 0, &dst, sizeof(T));
}

template<typename T>
void put(int pid, T& source, T& dst) {
	bsp_put(pid, &source, &dst, 0, sizeof(int));
}

void sync() {
	bsp_sync();
}

using pid_t = MCBSP_PROCESSOR_INDEX_DATATYPE;

pid_t pid() {
	return bsp_pid();
}

pid_t nprocs() {
	return bsp_nprocs();
}

template<typename T>
void pop_reg(T& t) {
	bsp_pop_reg(&t);
	bsp_sync();
}

template<typename T, typename... Args>
void pop_reg(T& t, Args... args) {
	pop_reg(t);
	pop_reg(args...);
}

template<typename T>
struct Register {
	T& t;
	Register(T& t) : t{t} 	{ push_reg(t); }
	~Register() 			{ pop_reg(t);  }
	T get_sync(int pid) {
		T res;
		Bsp::get(pid, t, res);
		sync();
		return res;
	}
};

//[[ noreturn ]]
void abort(std::string s)  {
	bsp_abort(const_cast<char*>(s.c_str()));
	//exit(1);
}

} // namespace Bsp




#endif /* BSP_HPP_ */
